package com.dict.modules.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Json工具类
 */
public class JsonUtil {

    private final static Logger log = LoggerFactory.getLogger(JsonUtil.class);

    /**
     * 对象字段映射
     *
     * @param source 待转换的原json字符串
     * @param keys   源字段目标字段映射  示例 oldName1,newName1,oldName2,newName2
     * @throws RuntimeException 运行异常
     */
    public static String map(String source, String... keys) throws RuntimeException {
        log.debug("执行com.bsd.integration.center.utils.JsonUtil.map入口，参数{},{}", source, keys);
        if (keys == null || keys.length == 0 || keys.length % 2 != 0) {
            log.warn("执行com.bsd.integration.center.utils.JsonUtil.map，参数keys不能为空，且必须是偶数，无效的参数keys:{}", Arrays.toString(keys));
            throw new RuntimeException("参数keys不能为空，且必须是偶数，无效的参数keys：" + Arrays.toString(keys));
        }
        List<MapKey> list = new ArrayList<>();
        MapKey mapKey = null;
        for (int i = 0, size = keys.length; i < size; i++) {
            if (NumberUtil.isEven(i)) {
                mapKey = MapKey.builder().build();
                mapKey.setOldName(keys[i]);
            } else {
                mapKey.setNewName(keys[i]);
                list.add(mapKey);
            }
        }
        return mapByMapKeys(source, list);
    }

    /**
     * 对象字段映射
     *
     * @param source 待转换的原json字符串
     * @param keys   源字段目标字段映射  格式 oldName1,newName1,level1,oldName2,newName2,level2 示例 name,userName,1,addr,address,2
     * @throws RuntimeException 运行异常
     */
    public static String mapByLevel(String source, String... keys) throws RuntimeException {
        log.debug("执行com.bsd.integration.center.utils.JsonUtil.map入口，参数{},{}", source, keys);
        if (keys == null || keys.length == 0 || keys.length % 3 != 0) {
            log.warn("执行com.bsd.integration.center.utils.JsonUtil.map，参数keys不能为空，且必须是偶数，无效的参数keys:{}", Arrays.toString(keys));
            throw new RuntimeException("参数keys不能为空，且必须是偶数，无效的参数keys：" + Arrays.toString(keys));
        }
        List<MapKey> list = new ArrayList<>();
        MapKey mapKey = null;
        for (int i = 0, size = keys.length; i < size; i++) {
            String key = keys[i];
            if (i % 3 == 0) {
                mapKey = MapKey.builder().build();
                mapKey.setOldName(key);
            } else if (i % 3 == 1) {
                mapKey.setNewName(key);
            } else {
                mapKey.setLevel(Integer.valueOf(key));
                list.add(mapKey);
            }
        }
        return mapByMapKeys(source, list);
    }

    /**
     * 对象字段映射
     *
     * @param source   待转换的原json字符串
     * @param keysList 源字段目标字段映射  示例 [
     *                 {
     *                 "oldName": "name",
     *                 "newName": "JSON新的key名字"
     *                 }
     *                 ]
     * @throws RuntimeException 运行异常
     */
    public static String map(String source, List<Map<String, String>> keysList) throws RuntimeException {
        log.debug("执行com.bsd.integration.center.utils.JsonUtil.map入口，参数{},{}", source, keysList);
        String jsonStr = JSONUtil.toJsonStr(keysList);
        List<MapKey> mapKeyList = JSONUtil.toList(jsonStr, MapKey.class);
        return mapByMapKeys(source, mapKeyList);
    }


    /**
     * 对象字段映射
     *
     * @param source  待转换的原json字符串
     * @param jsonStr 源字段目标字段映射  示例 [{"oldName": "name","newName": "JSON新的key名字"}]
     * @throws RuntimeException 运行异常
     */
    public static String map(String source, String jsonStr) throws RuntimeException {
        log.debug("执行com.bsd.integration.center.utils.JsonUtil.map入口，参数{},{}", source, jsonStr);
        List<MapKey> mapKeyList = JSONUtil.toList(jsonStr, MapKey.class);
        return mapByMapKeys(source, mapKeyList);
    }

    /**
     * 对象字段映射
     *
     * @param source 待转换的原json字符串
     * @param keys   源字段目标字段映射
     * @throws RuntimeException 运行异常
     */
    public static String mapByMapKeys(String source, List<MapKey> keys) throws RuntimeException {
        log.debug("执行com.bsd.integration.center.utils.JsonUtil.mapByMapKeys入口，参数{},{}", source, keys);
        if (!JSONUtil.isTypeJSON(source)) {
            log.error("执行com.bsd.integration.center.utils.JsonUtil.mapByMapKeys，无效的源JSON字符串source:{}", source);
            throw new RuntimeException("无效的源JSON字符串source:" + source);
        }
        JSON json = null;
        try {
            json = JSONUtil.parse(source);
        } catch (Exception e) {
            log.error("执行com.bsd.integration.center.utils.JsonUtil.mapByMapKeys，无效的源JSON字符串source:{}", source);
            throw new RuntimeException("无效的源JSON字符串source:" + source);
        }
        recursiveMap(json, keys, 1);
        return JSONUtil.toJsonStr(json);
    }

    /**
     * 多层嵌套的复杂JSON对象进行递归映射处理
     *
     * @param json  待转换的原json字符串
     * @param keys  映射关系列表
     * @param level 层级
     */
    private static void recursiveMap(JSON json, List<MapKey> keys, int level) {
        List<MapKey> filteredKeys = keys.stream().filter(e -> Objects.isNull(e.getLevel()) || 0 == e.getLevel() || e.getLevel() == level).collect(Collectors.toList());
        if (json instanceof JSONArray) {
            JSONArray jsonArray = (JSONArray) json;
            for (Object obj : jsonArray) {
                if (obj instanceof JSONObject) {
                    JSONObject jsonObject = (JSONObject) obj;
                    doMapping(jsonObject, filteredKeys);
                    // 值类型如果是JSON 则递归调用本方法
                    jsonObject.values().stream().forEach(v -> {
                        if (v instanceof JSON) {
                            recursiveMap((JSON) v, keys, level + 1);
                        }
                    });
                }
            }
        } else if (json instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) json;
            doMapping(jsonObject, filteredKeys);
            jsonObject.values().stream().forEach(v -> {
                if (v instanceof JSON) {
                    recursiveMap((JSON) v, keys, level + 1);
                }
            });
        }
    }

    /**
     * 处理key的映射
     *
     * @param jsonObject   待处理的jsonObject对象
     * @param filteredKeys 需要出来的key列表
     */
    private static void doMapping(JSONObject jsonObject, List<MapKey> filteredKeys) {
        Map<String, Object> map = jsonObject.getRaw();
        List<String> oldNames = filteredKeys.stream().map(MapKey::getOldName).collect(Collectors.toList());
        Map<String, Object> addMap = new HashMap<>();
        map.keySet().removeIf(k -> {
            if (oldNames.contains(k)) {
                List<MapKey> list = filteredKeys.stream().filter(e -> e.getOldName().equals(k)).collect(Collectors.toList());
                MapKey mapKey = list.get(0);
                String newName = mapKey.getNewName();
                addMap.put(newName, map.get(k));
                return true;
            }
            return false;
        });
        if (CollUtil.isNotEmpty(addMap)) {
            map.putAll(addMap);
        }

    }


    public static void main(String[] args) {


        String jsonStr = "{\n" + "    \"schoolName\": \"ECNU\",\n" + "    \"name\": \"ECNU\",\n" + "    \"address\": \"Road\",\n" + "    \"student\": [\n" + "        {\n" + "            \"name\": \"Tom\",\n" + "            \"Grade\": 1,\n" + "            \"age\": 11,\n" + "            \"gender\": \"M\"\n" + "        },\n" + "        {\n" + "            \"name\": \"Jerry\",\n" + "            \"Grade\": 1,\n" + "            \"age\": 10,\n" + "            \"gender\": \"M\"\n" + "        }\n" + "    ],\n" + "    \"classroom\": {\n" + "        \"class1\": {\n" + "            \"name\": \"一年级一班\",\n" + "            \"position\": \"fifth floor\"\n" + "        },\n" + "        \"class2\": {\n" + "            \"name\": \"一年级二班\",\n" + "            \"position\": \"seventh floor\"\n" + "        }\n" + "    }\n" + "}";
        // 测试可变参数
        System.out.println("可变参数 :" + JsonUtil.map(jsonStr, "name", "newName", "schoolName", "schoolName999999"));

        // 测试可变参数 指定参数level
        System.out.println("可变参数 指定参数level :" + JsonUtil.mapByLevel(jsonStr, "name", "newName", "2", "schoolName", "schoolName999999", "0", "name", "className", "3"));

        // 测试字符串传值
        String str = "[{\"newName\":\"newname\",\"oldName\":\"name\"}]";
        System.out.println(" String :" + JsonUtil.map(jsonStr, str));


        // 测试List<Map<String, String>>传值
        List<Map<String, String>> list2 = new ArrayList<>();
        Map<String, String> map = new HashMap<>();
        map.put(MapKey.OLD_NAM, "name");
        map.put(MapKey.NEW_NAM, "newname");
        list2.add(map);
        System.out.println(" List<Map<String, String>>   :" + JsonUtil.map(jsonStr, list2));


        // 测试List<MapKey>传值
        MapKey key1 = new MapKey();
        key1.setOldName("address").setNewName("addressNew"); // 不设置level 默认全局替换

        MapKey key2 = new MapKey();
        key2.setOldName("name").setNewName("newname");

        MapKey key3 = new MapKey();
        key3.setOldName("class1").setNewName("newclass1");

        List<MapKey> list = new ArrayList<>();
        list.add(key1);
        list.add(key2);
        list.add(key3);
        System.out.println("mapByMapKeys   :" + JsonUtil.mapByMapKeys(jsonStr, list));

    }
}
